package com.sailing.xjpb.orm.utils;

import com.sailing.xjpb.common.SailingAssert;
import com.sailing.xjpb.common.SailingReflectionUtils;
import org.apache.commons.lang3.StringUtils;

import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Table;
import java.lang.reflect.Field;

/**
 * jpa工具类，用于获取ID|表名称|字段名称等信息
 *
 * @author YaoWei createDate 2020/12/1
 */
public final class JpaUtils {

    private JpaUtils() {

    }

    /**
     * 为了解决Neo4j实体不使用注解javax.persistence.Id问题
     */
    private static final String DEFAULT_ID_FIELD_NAME = "id";

    /**
     * 获取标注有注解Id的字段
     *
     * @param entity 实体对象信息
     * @return id字段的值
     * @author YaoWei createDate 2020年11月19日 下午1:14:04
     */
    public static Object getIdFieldValue(Object entity) {
        Class<?> clazz = entity.getClass();
        Field idField = getIdField(clazz);
        return SailingReflectionUtils.getField(idField, entity);
    }

    /**
     * 获取标注有注解Id的字段
     *
     * @param clazz 实体类字节码信息
     * @return 字段信息
     * @author YaoWei createDate 2020年11月19日 下午1:14:04
     */
    public static Field getIdField(Class<?> clazz) {
        Field idField = SailingReflectionUtils.getDeclaredField(clazz,
                (field -> field.getAnnotation(Id.class) != null || DEFAULT_ID_FIELD_NAME.equals(field.getName())));
        SailingAssert.notNull(idField, "实体" + clazz.getName() + "未标注@Id注解或没有使用默认的主键ID!");
        return idField;
    }

    /**
     * 根据字段获取字段名称（如果没有标注@Column将返回field的名称）
     *
     * @param field 字段信息
     * @return 数据库字段名称
     */
    public static String getColumnName(Field field) {
        Column column = field.getAnnotation(Column.class);
        return (column != null && StringUtils.isNotEmpty(column.name())) ? column.name() : field.getName();
    }

    /**
     * 根据@Column#name获取字段名称
     *
     * @param clazz      类信息
     * @param columnName @Column#name
     * @return 字段名称
     */
    public static String getFieldName(Class<?> clazz, String columnName) {
        Field columnField = SailingReflectionUtils.getDeclaredField(clazz,
                field -> {
                    Column column = field.getAnnotation(Column.class);
                    if (column == null) {
                        return false;
                    }
                    return column.name().equalsIgnoreCase(columnName);
                });
        SailingAssert.notNull(columnField, "实体" + clazz.getName() + "未标注@Id注解或没有使用默认的主键ID!");
        return columnField.getName();
    }

    /**
     * 获取实体配置的表名
     *
     * @param entityClass 实体类字节码信息
     * @return 表名称
     */
    public static String getTableName(Class<?> entityClass) {
        Table table = entityClass.getAnnotation(Table.class);
        SailingAssert.notNull(entityClass, "实体" + entityClass.getName() + "未标注@Table注解!");
        return table.name();
    }

    /**
     * 判断实体是否是新增，主键ID值为空则是新增
     *
     * @param entity 实体信息
     * @return 是否是新实体
     */
    public static boolean isNewEntity(Object entity) {
        Object idFieldValue = getIdFieldValue(entity);
        return idFieldValue == null || "".equals(idFieldValue);
    }

}
